home *** CD-ROM | disk | FTP | other *** search
- /*
- * (c) Copyright 1992 by Panagiotis Tsirigotis
- * All rights reserved. The file named COPYRIGHT specifies the terms
- * and conditions for redistribution.
- */
-
- static char RCSid[] = "$Id" ;
-
- #include <sys/types.h>
- #include <netdb.h>
- #include <string.h>
- #include <syslog.h>
- #include <memory.h>
-
- #include "misc.h"
- #include "str.h"
- #include "pset.h"
- #include "fsma.h"
- #include "sio.h"
-
- #include "defs.h"
- #include "service.h"
- #include "conf.h"
- #include "attr.h"
- #include "parse.h"
- #include "addr.h"
-
- char *malloc() ;
- void endprotoent() ;
- void endpwent() ;
- void endgrent() ;
- int endnetent() ;
- void endhostent() ;
-
-
- void parsemsg() ;
- void msg() ;
- void out_of_memory() ;
-
- char *next_line() ;
- int line_has_only_1_char() ;
-
- /*
- * Parser functions
- */
- status_e service_parser() ;
- status_e socket_type_parser() ;
- status_e protocol_parser() ;
- status_e wait_parser() ;
- status_e user_parser() ;
- status_e group_parser() ;
- status_e server_parser() ;
- status_e server_args_parser() ;
- status_e instances_parser() ;
- status_e log_on_success_parser() ;
- status_e log_on_failure_parser() ;
- status_e log_type_parser() ;
- status_e only_from_parser() ;
- status_e no_access_parser() ;
- status_e access_times_parser() ;
- status_e type_parser() ;
- status_e id_parser() ;
- status_e env_parser() ;
- status_e port_parser() ;
- status_e rpc_version_parser() ;
- status_e passenv_parser() ;
- status_e flags_parser() ;
- status_e disabled_parser() ;
-
- /*
- * A NULL value for the name field marks the end of the table
- *
- * The 3rd value is the number of attribute values.
- * If the number is positive, exactly that many values must be specified.
- * If the number is -1, 0 or more values may be specified.
- * If the number is -2, 0 or more values may be specified and the operators
- * '+=' and '-=' may be used.
- */
- static struct attribute service_attributes[] =
- {
- { "socket_type", A_SOCKET_TYPE, 1, socket_type_parser },
- { "protocol", A_PROTOCOL, 1, protocol_parser },
- { "wait", A_WAIT, 1, wait_parser },
- { "user", A_USER, 1, user_parser },
- { "group", A_GROUP, 1, group_parser },
- { "server", A_SERVER, 1, server_parser },
- { "server_args", A_SERVER_ARGS, -1, server_args_parser },
- { "instances", A_INSTANCES, 1, instances_parser },
- { "log_on_success", A_LOG_ON_SUCCESS, -2, log_on_success_parser },
- { "log_on_failure", A_LOG_ON_FAILURE, -2, log_on_failure_parser },
- { "log_type", A_LOG_TYPE, -1, log_type_parser },
- { "only_from", A_ONLY_FROM, -2, only_from_parser },
- { "no_access", A_NO_ACCESS, -2, no_access_parser },
- { "access_times", A_ACCESS_TIMES, -1, access_times_parser },
- { "type", A_TYPE, -1, type_parser },
- #ifndef NO_RPC
- { "rpc_version", A_RPC_VERSION, 1, rpc_version_parser },
- #endif
- { "id", A_ID, 1, id_parser },
- { "env", A_ENV, -2, env_parser },
- { "port", A_PORT, 1, port_parser },
- { "passenv", A_PASSENV, -2, passenv_parser },
- { "flags", A_FLAGS, -1, flags_parser },
- { NULL, A_NONE, -1, NULL }
- } ;
-
- static struct attribute default_attributes[] =
- {
- { "log_type", A_LOG_TYPE, -2, log_type_parser },
- { "log_on_success", A_LOG_ON_SUCCESS, -2, log_on_success_parser },
- { "log_on_failure", A_LOG_ON_FAILURE, -2, log_on_failure_parser },
- { "disabled", A_DISABLED, -2, disabled_parser },
- { "no_access", A_NO_ACCESS, -2, no_access_parser },
- { "only_from", A_ONLY_FROM, -2, only_from_parser },
- { "instances", A_INSTANCES, 1, instances_parser },
- { "passenv", A_PASSENV, -2, passenv_parser },
- { NULL, A_NONE, 0, NULL }
- } ;
-
-
- #define MODIFIABLE( ap ) ( (ap)->n_values == -2 )
- #define VAR_VALUES( ap ) ( (ap)->n_values < 0 )
- #define FIXED_VALUES( ap ) ( (ap)->n_values > 0 )
-
- int line_count ;
-
-
-
- /*
- * Given the id, return the name (only the service attributes are searched)
- */
- char *attr_name_lookup( id )
- register int id ;
- {
- register struct attribute *ap ;
-
- for ( ap = &service_attributes[ 0 ] ; ap->name != NULL ; ap++ )
- if ( id == ap->id )
- return( ap->name ) ;
- return( NULL ) ;
- }
-
-
- /*
- * Parsing rules and rationale
- *
- * The parse_conf_file function parses a configuration file identified
- * by a file descriptor and fills the service table and defaults of
- * the configuration argument.
- *
- * The configuration information for a service comes from 2 sources: the
- * service entry and, possibly, the defaults entry.
- * Attributes specified in the defaults entry can be overriden or
- * modified by the service entry. Modifiable attributes can be identified
- * by the value -2 for the 'n_values' field of the struct attribute. Those
- * attributes with a different value for 'n_values' are overridable ones.
- * The modifiable attributes are filled in only if the entry tries to modify
- * them.
- */
-
- /*
- * Read the configuration file (descriptor fd) and place all
- * services found there in the configuration.
- */
- void parse_conf_file( fd, confp )
- int fd ;
- struct configuration *confp ;
- {
- pset_h stab = confp->services ;
- struct service_config *default_config = CONF( confp->defaults ) ;
- struct service_config default_default_config ;
- boolean_e found_defaults = NO ;
- void get_service_entry() ;
- void skip_entry() ;
- entry_e find_next_entry() ;
- status_e parse_entry() ;
- char *func = "parse_conf_file" ;
-
- line_count = 0 ;
- CLEAR( default_default_config ) ;
-
- for ( ;; )
- {
- entry_e entry_type ;
- char *service_name ;
-
- /*
- * if find_next_entry is successful, service_name
- * will point to malloc'ed memory
- */
- entry_type = find_next_entry( fd, &service_name ) ;
- if ( entry_type == SERVICE_ENTRY )
- get_service_entry( fd, stab, service_name, default_config ) ;
- else if ( entry_type == DEFAULTS_ENTRY )
- {
- if ( found_defaults == YES )
- {
- parsemsg( LOG_ERR, func,
- "only 1 defaults entry is allowed. This entry will be ignored" ) ;
- skip_entry( fd ) ;
- }
- else if ( parse_entry( DEFAULTS_ENTRY, fd,
- default_config, &default_default_config ) == OK )
- found_defaults = YES ;
- }
- else
- break ;
- }
-
- endprotoent() ;
- endpwent() ;
- endgrent() ;
- endnetent() ;
- endhostent() ;
- }
-
-
- /*
- * Find the next service entry.
- * Look for a line of the form:
- *
- * <white-space> service <white-space> <service_name>
- *
- * followed by a line containing only the ENTRY_BEGIN character
- */
- PRIVATE entry_e find_next_entry( fd, snamep )
- int fd ;
- char **snamep ; /* service name pointer */
- {
- register char *line = next_line( fd ) ;
- register char *p ;
- str_h strp ;
- char *sname ;
- entry_e entry_type ;
- char *func = "find_next_entry" ;
-
- if ( line == NULL )
- return( NO_ENTRY ) ;
-
- strp = str_parse( line, " \t", STR_RETURN_ERROR, (int *)0 ) ;
- if ( strp == NULL )
- {
- parsemsg( LOG_CRIT, func, "str_parse failed" ) ;
- return( BAD_ENTRY ) ;
- }
- if ( ( p = str_component( strp ) ) == NULL )
- {
- /*
- * This shouldn't happen since it implies that there is a bug
- * in next_line
- */
- parsemsg( LOG_WARNING, func, "empty line" ) ;
- str_endparse( strp ) ;
- return( BAD_ENTRY ) ;
- }
-
- /*
- * Look for a keyword:
- * service: for a new service entry
- * defaults: for the defaults entry
- */
- if ( EQ( p, KW_SERVICE ) )
- {
- /*
- * Now get the service name
- */
- if ( ( p = str_component( strp ) ) == NULL )
- {
- parsemsg( LOG_ERR, func, "service name missing" ) ;
- str_endparse( strp ) ;
- return( BAD_ENTRY ) ;
- }
-
- sname = make_string( 1, p ) ;
- if ( sname == NULL )
- {
- out_of_memory( func ) ;
- str_endparse( strp ) ;
- return( BAD_ENTRY ) ;
- }
- str_endparse( strp ) ;
- entry_type = SERVICE_ENTRY ;
- }
- else if ( EQ( p, KW_DEFAULTS ) )
- {
- str_endparse( strp ) ;
- entry_type = DEFAULTS_ENTRY ;
- }
- else
- {
- parsemsg( LOG_ERR, func, "missing service keyword" ) ;
- str_endparse( strp ) ;
- return( BAD_ENTRY ) ;
- }
-
- /*
- * Now look for ENTRY_BEGIN
- */
- line = next_line( fd ) ;
- if ( line == NULL || ! line_has_only_1_char( line, ENTRY_BEGIN ) )
- {
- parsemsg( LOG_ERR, func,
- "Service %s: couldn't find %c", sname, ENTRY_BEGIN ) ;
- if ( entry_type == SERVICE_ENTRY )
- free( sname ) ;
- return( BAD_ENTRY ) ;
- }
- *snamep = sname ;
- return( entry_type ) ;
- }
-
-
-
- /*
- * Get a service entry. Steps:
- *
- * 1. Parse entry attributes
- * 2. Determine service id
- * 3. Insert entry in service table
- */
- PRIVATE void get_service_entry( fd, stab, name, defaults )
- int fd ;
- pset_h stab ;
- char *name ;
- struct service_config *defaults ;
- {
- struct service_config sconf ;
- register struct service_config *scp = &sconf ;
- unsigned u ;
- char *func = "get_service_entry" ;
- status_e parse_entry() ;
-
- CLEAR( sconf ) ;
- scp->name = name ;
-
- if ( parse_entry( SERVICE_ENTRY, fd, scp, defaults ) == FAILED )
- {
- sconf_free( scp ) ;
- skip_entry( fd ) ;
- return ;
- }
-
- /*
- * If no service id was specified, set it equal to the service name
- */
- if ( ! SPECIFIED( scp, A_ID ) )
- if ( scp->id = make_string( 1, scp->name ) )
- PRESENT( scp, A_ID ) ;
- else
- {
- out_of_memory( func ) ;
- sconf_free( scp ) ;
- return ;
- }
-
- /*
- * Look it up
- */
- for ( u = 0 ; u < pset_count( stab ) ; u++ )
- if ( EQ( CONF( SP( pset_pointer( stab, u ) ) )->id, scp->id ) )
- {
- parsemsg( LOG_ERR, func, "id not unique: %s", scp->id ) ;
- sconf_free( scp ) ;
- return ;
- }
-
- if ( svc_alloc( scp, stab ) == NULL )
- {
- sconf_free( scp ) ;
- return ;
- }
- }
-
-
- #define INIT_PSET( pset ) \
- if ( pset == NULL && ( pset = pset_create( 10, 10 ) ) == NULL ) \
- { \
- out_of_memory( func ) ; \
- return( FAILED ) ; \
- }
-
- /*
- * Read the entry line-by-line and add the information in scp
- * Use defaults to initialize modifiable entry fields.
- */
- PRIVATE status_e parse_entry( entry_type, fd, scp, defaults )
- entry_e entry_type ;
- int fd ;
- struct service_config *scp ;
- struct service_config *defaults ;
- {
- static pset_h attr_values ;
- register char *line ;
- char *attr_name ;
- enum assign_op op ;
- void identify_attribute() ;
- status_e parse_line() ;
- char *func = "get_attributes" ;
-
- INIT_PSET( attr_values ) ;
-
- for ( ;; )
- {
- line = next_line( fd ) ;
- if ( line == NULL )
- {
- parsemsg( LOG_ERR, func, "incomplete entry" ) ;
- return( FAILED ) ;
- }
-
- if ( line_has_only_1_char( line, ENTRY_END ) )
- return( OK ) ;
-
- if ( parse_line( line, &attr_name, &op, attr_values ) == FAILED )
- {
- pset_clear( attr_values ) ;
- return( FAILED ) ;
- }
-
- identify_attribute( entry_type,
- scp, defaults, attr_name, op, attr_values ) ;
- pset_clear( attr_values ) ;
- }
- }
-
-
-
- /*
- * Find the attribute with the specified name
- */
- PRIVATE struct attribute *attr_lookup( attr_array, attr_name )
- struct attribute attr_array[] ;
- char *attr_name ;
- {
- register struct attribute *ap ;
- char *func = "attr_lookup" ;
-
- for ( ap = &attr_array[ 0 ] ; ap->name != NULL ; ap++ )
- if ( EQ( attr_name, ap->name ) )
- return( ap ) ;
- parsemsg( LOG_WARNING, func, "bad attribute: %s", attr_name ) ;
- return( NULL ) ;
- }
-
-
- /*
- * Identify the attribute in <attr_name>.
- *
- * Check if
- * 1) the attribute has been defined already
- * 2) the value count is correct
- * 3) the assign op is appropriate
- *
- * Invoke appropriate parser
- */
- PRIVATE void identify_attribute( entry_type, scp, defaults,
- attr_name, op, attr_values )
- entry_e entry_type ;
- struct service_config *scp ;
- struct service_config *defaults ;
- register char *attr_name ;
- enum assign_op op ;
- pset_h attr_values ;
- {
- register struct attribute *ap ;
- char *func = "identify_attribute" ;
- void fill_attribute() ;
-
- if ( entry_type == SERVICE_ENTRY )
- ap = attr_lookup( service_attributes, attr_name ) ;
- else
- ap = attr_lookup( default_attributes, attr_name ) ;
-
- if ( ap == NULL )
- return ;
-
- if ( ! MODIFIABLE( ap ) )
- {
- if ( SPECIFIED( scp, ap->id ) )
- {
- parsemsg( LOG_WARNING, func,
- "Service %s: attribute already set: %s",
- scp->name, attr_name ) ;
- return ;
- }
-
- if ( op != SET_EQ )
- {
- parsemsg( LOG_WARNING, func,
- "Service %s: operator %s cannot be used for attribute %s",
- scp->name, ( op == PLUS_EQ ) ? "+=" : "-=", attr_name ) ;
- return ;
- }
- }
- else
- {
- if ( entry_type == DEFAULTS_ENTRY && op == SET_EQ )
- op = PLUS_EQ ;
- if ( ! IS_PRESENT( scp, ap->id ) && SPECIFIED( defaults, ap->id ) )
- fill_attribute( ap->id, scp, defaults ) ;
- }
-
- if ( FIXED_VALUES( ap ) && ap->n_values != pset_count( attr_values ) )
- {
- parsemsg( LOG_WARNING, func,
- "attribute %s expects %d values and %d values were specified",
- attr_name, ap->n_values, pset_count( attr_values ) ) ;
- return ;
- }
-
- if ( (*ap->parser)( attr_values, scp, op ) == OK )
- SPECIFY( scp, ap->id ) ;
- }
-
-
-
- /*
- * Fill in scp the value of the modifiable attribute attr from def.
- * These modifiable attributes are:
- * log_on_{success,failure}
- * only_from
- * no_access
- * passenv
- */
- PRIVATE void fill_attribute( attr_id, scp, def )
- unsigned attr_id ;
- struct service_config *scp ;
- struct service_config *def ;
- {
- status_e list_assign() ;
- status_e copy_pset() ;
-
- switch ( attr_id )
- {
- case A_LOG_ON_SUCCESS:
- M_ASSIGN( scp->log_on_success, def->log_on_success ) ;
- PRESENT( scp, A_LOG_ON_SUCCESS ) ;
- break ;
-
- case A_LOG_ON_FAILURE:
- M_ASSIGN( scp->log_on_failure, def->log_on_failure ) ;
- PRESENT( scp, A_LOG_ON_FAILURE ) ;
- break ;
-
- case A_ONLY_FROM:
- if ( addrlist_copy( def->only_from, &scp->only_from ) == OK )
- PRESENT( scp, A_ONLY_FROM ) ;
- break ;
-
- case A_NO_ACCESS:
- if ( addrlist_copy( def->no_access, &scp->no_access ) == OK )
- PRESENT( scp, A_NO_ACCESS ) ;
- break ;
-
- case A_PASSENV:
- if ( copy_pset( def->passenv, &scp->passenv, (fsma_h) NULL ) == OK )
- PRESENT( scp, A_PASSENV ) ;
- break ;
- }
- }
-
-
-
-
- /*
- * Parse a line of the form:
- * name OP value value value ...
- * where each value is a string and OP can be '=', '+=', '-='
- *
- * NOTE: We do not allocate space for the name and values. Instead we keep
- * pointers to the line.
- */
- PRIVATE status_e parse_line( line, namep, opp, values )
- char *line ;
- char **namep ;
- enum assign_op *opp ;
- pset_h values ;
- {
- char *value ;
- char *values_string ;
- char *attribute ;
- str_h strp ;
- char *func = "parse_line" ;
- char *get_attr_op() ;
-
- if ( ( values_string = get_attr_op( line, &attribute, opp ) ) == NULL )
- return( FAILED ) ;
-
- /*
- * Now grab the values
- */
- strp = str_parse( values_string, " \t", STR_RETURN_ERROR, (int *)0 ) ;
- if ( strp == NULL )
- {
- parsemsg( LOG_CRIT, func, "out of memory" ) ;
- return( FAILED ) ;
- }
-
- while ( value = str_component( strp ) )
- {
- if ( pset_add( values, value ) == NULL )
- {
- parsemsg( LOG_CRIT, func,
- "Out of memory (attribute = %s)", attribute ) ;
- str_endparse( strp ) ;
- return( FAILED ) ;
- }
- }
-
- str_endparse( strp ) ;
- *namep = attribute ;
- return( OK ) ;
- }
-
-
- /*
- * Input:
- * a line of the form
- * name [SPACE] OP [SPACE] value [SPACE] value ...
- *
- * Recognize the attribute name and operator and place them in *attrp, *opp
- *
- * Currently, we allow any non-space character to be used in the
- * attribute name.
- *
- * Return value: a pointer to the character after OP.
- */
- PRIVATE char *get_attr_op( line, attrp, opp )
- char *line ;
- char **attrp ;
- enum assign_op *opp ;
- {
- register char *p ;
- char *attr ;
- enum assign_op op ;
- char *func = "get_attr_op" ;
-
- /*
- * First get the attribute name
- */
- for ( p = line ; isspace( *p ) ; p++ ) ; /* skip spaces */
- if ( *p == NUL )
- {
- parsemsg( LOG_ERR, func, "Empty line" ) ;
- return( NULL ) ;
- }
-
- attr = p ;
- for ( ; ! isspace( *p ) ; p++ ) ; /* skip attribute name */
- if ( *p == NUL )
- {
- parsemsg( LOG_ERR, func, "Nothing after attribute: %s", attr ) ;
- return( NULL ) ;
- }
- *p++ = NUL ; /* now attribute name is NUL terminated */
-
-
- for ( ; isspace( *p ) ; p++ ) ; /* skip spaces */
-
- switch ( *p )
- {
- case NUL:
- parsemsg( LOG_ERR, func, "Nothing after attribute: %s", attr ) ;
- return( NULL ) ;
-
- case '=':
- op = SET_EQ ;
- break ;
-
- case '+':
- case '-':
- op = ( *p++ == '+' ) ? PLUS_EQ : MINUS_EQ ;
- if ( *p == '=' )
- break ;
-
- /* FALL THROUGH if there is no '=' after the '+' or '-' */
-
- default:
- parsemsg( LOG_ERR, func, "Bad operator for attribute: %s", attr ) ;
- return( NULL ) ;
- }
- *attrp = attr ;
- *opp = op ;
- return( ++p ) ; /* skip the '=' */
- }
-
-
- PRIVATE void skip_entry( fd )
- register int fd ;
- {
- for ( ;; )
- {
- register char *line = next_line( fd ) ;
-
- if ( line == NULL ) /* reached EOF ? */
- {
- parsemsg( LOG_WARNING, "skip_entry",
- "missing %c in last service entry", ENTRY_END ) ;
- break ;
- }
-
- if ( line_has_only_1_char( line, ENTRY_END ) )
- break ;
- }
- }
-
-
-
- /*
- * next_line returns the next line of the file or NULL if the end of file
- * is reached.
- * Comment lines and empty lines are skipped.
- */
- PRIVATE char *next_line( fd )
- int fd ;
- {
- for ( ;; )
- {
- register char *p ;
- register char *line = Srdline( fd ) ;
-
- if ( line == NULL )
- return( NULL ) ;
-
- line_count++ ;
-
- for ( p = line ;; p++ )
- if ( *p == NUL || *p == COMMENT_BEGIN )
- break ; /* skip this line */
- else if ( isspace( *p ) )
- continue ; /* skip white space */
- else
- return( line ) ;
- }
- }
-
-
-
- /*
- * Returns TRUE if the given line contains a single instance of the
- * specified character and no other non-space characters
- */
- PRIVATE int line_has_only_1_char( line, ch )
- char *line ;
- char ch ;
- {
- register char *p ;
- register char target_char = ch ;
-
- for ( p = line ; *p ; p++ )
- if ( *p == target_char )
- target_char = NUL ;
- else if ( ! isspace( *p ) )
- return( FALSE ) ;
- return( target_char != ch ) ;
- }
-
-
-